from Token import *
from SyntaticError import *
from Constants import *

from lexico import *
from semantico import *

class sintatico:
	def __init__(self):
		self._currentToken = None
		self._previousToken = None
		self._stack = None

	def parse(self, scanner, semanticAnalyser):

		self.scanner = scanner
		self.semanticAnalyser = semanticAnalyser

		self._stack = []
		self._stack.append(DOLLAR)
		self._stack.append(START_SYMBOL)

		if self._previousToken and self._previousToken != self._currentToken:
			del self._previousToken
		self._previousToken = None

		self._currentToken = scanner.nextToken()

		while not self.step(): pass

	def step(self):

		if not self._currentToken:
			pos = 0
			if self._previousToken:
				pos = self._previousToken.getPosition() + len(self._previousToken.getLexeme())
		
			self._currentToken = Token(DOLLAR, '$', pos)

		a = self._currentToken.getId()
		x = self._stack[-1]
		self._stack.pop()

		if x == EPSILON:
			return False

		if self.isTerminal(x):
		
			if x == a:
				if len(self._stack) == 0:
					return True
		
				self._previousToken = self._currentToken
				self._currentToken = self.scanner.nextToken()

				return False

			raise SyntaticError(PARSER_ERROR[x], self._currentToken.getPosition())

		if self.isNonTerminal(x):

			if self.pushProduction(x, a):
				return False
			
			raise SyntaticError(PARSER_ERROR[x], self._currentToken.getPosition())

		self.semanticAnalyser.executeAction(x-FIRST_SEMANTIC_ACTION, self._previousToken)

		return False

	def pushProduction(self, topStack, tokenInput):

		p = PARSER_TABLE[topStack-FIRST_NON_TERMINAL][tokenInput-1]

		if p >= 0:
			length = PRODUCTIONS[p][0]
			for i in range(length, 0, -1):
				self._stack.append(PRODUCTIONS[p][i])

			return True

		return False

	def isTerminal(self, x):

		return x < FIRST_NON_TERMINAL

	def isNonTerminal(self, x):

		return (x >= FIRST_NON_TERMINAL) and (x < FIRST_SEMANTIC_ACTION)

	def isSemanticAction(self, x):

		return x >= FIRST_SEMANTIC_ACTION

if __name__ == '__main__':

	from lexico import *
	from semantico import *

	text = 'program _teAAste'
	
	lex = lexico(text)
	sin = sintatico()
	sem = semantico()

	try:
		sin.parse(lex, sem)
	except Exception, e:
		print e.__module__ 
		print e.getMessage()
		print type(e)

